#include "guish.hpp"
#ifndef SHELLCOMMAND_HPP
#define SHELLCOMMAND_HPP
#include "IOManager.hpp"

class Redirection;
class FdCloser;

class ShellCommand
{
public:
	ShellCommand();
	virtual ~ShellCommand();
	virtual int execute(ExecutionEnvironment *execEnvironment, Job *context)=0;
	virtual string toString()=0;
	
	bool getRunInBackground();
	void setRunInBackground(bool runInBackground);
	
protected:
	bool runInBackground;
	
};

class SimpleShellCommand
	:public ShellCommand
{
public:
	~SimpleShellCommand();
	
	int execute(ExecutionEnvironment *execEnvironment, Job *context);
	void addToken(Token tok);
	void addRedirection(Redirection *redir);
	string toString();
	
	void begin(ExecutionEnvironment *execEnvironment, Job *context);
	int waitForFinish(Job *context);
	
protected:
	bool setupRedirects(FdCloser *fdCloser, ExecutionEnvironment *execEnv, Job *context);
	Process *runProgram(const vector<string> &params, Job *context, const ExecutionEnvironment *execEnv);
	int forkProcess(const ExecutionEnvironment *context, const char *program, int argc, char **argv, char **envVars);
	bool needsPathLookup(const char *str);
	
	list<Token> tokens;
	vector<Redirection*> redirections;
	int childPid;
	int builtinRet;
};

class PipeCommand
	:public ShellCommand
{
public:
	void addCommand(SimpleShellCommand *command);
	int execute(ExecutionEnvironment *execEnvironment, Job *context);
	string toString();
	
protected:
	vector<SimpleShellCommand*> commands;
};

class SequenceCommand
	:public ShellCommand
{
public:
	SequenceCommand();
	~SequenceCommand();
	
	int execute(ExecutionEnvironment *execEnvironment, Job *context);
	string toString();
	void addCommand(ShellCommand *command, int op);
	
protected:
	vector<ShellCommand*> commands;
	vector<int> ops;
};
#define SEQUENCE_SEMICOLON 0
#define SEQUENCE_AND 1
#define SEQUENCE_OR 2

class IfCommand
	:public ShellCommand
{
public:
	IfCommand(ShellCommand *condition, ShellCommand *trueBranch, ShellCommand *falseBranch);
	~IfCommand();
	
	int execute(ExecutionEnvironment *execEnvironment, Job *context);
	string toString();
	
protected:
	ShellCommand *condition;
	ShellCommand *trueBranch;
	ShellCommand *falseBranch;
};

class Redirection
{
public:
	Redirection();
	void setType(int type);
	void addToken(Token tok);
	string toString();
	
	int type;
	list<Token> tokens;
};
#define REDIR_SENDTO 0
#define REDIR_APPENDTO 1
#define REDIR_READFROM 2

class FdCloser
{
public:
	~FdCloser();
	void addFd(int fd);
protected:
	vector<int> fds;
};

#endif
